﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Wise.Util;

namespace Wise.Entities
{
    public class MyLogger
    {
        public static MyLogger Current { get; private set; }

        static MyLogger()
        {
            Current = new MyLogger();
        }

        public static void UseNewLogger()
        {
            Current = new MyLogger();
        }

        private MyLogger()
        {
            Id = DateTime.Now.ToString("yyyy-MM-dd.HH-mm");
            _INIT_DIR();
        }


        void InitWriter(string name, string fileId, string content)
        {
            _INIT_DIR();
            string currentLog1 = LogDir;// Path.Combine(LogDir, name);
            string currentLog2 = Path.Combine(currentLog1, string.Format("{0}.{1}.txt", name, fileId));
            if (!File.Exists(currentLog2))
            {
                lock (currentLog1)
                {
                    if (!DirFileHelper.IsExistDirectory(currentLog1))
                        DirFileHelper.CreateDirectory(currentLog1);
                }
                lock (currentLog2)
                {
                    if (!File.Exists(currentLog2))
                    {
                        using (FileStream fs = File.Create(currentLog2))
                        {
                            fs.Close();
                            Thread.Sleep(10);
                        }
                    }
                }
            }
            if (!_Data.ContainsKey(currentLog2))
            {
                lock (currentLog2)
                {
                    if (!_Data.ContainsKey(currentLog2))
                    {
                        try
                        {
                            _Data.TryAdd(currentLog2, new ConcurrentQueue<string>());
                        }
                        catch (Exception)
                        {
                            if (!_Data.ContainsKey(currentLog2))
                                _Data.TryAdd(currentLog2, new ConcurrentQueue<string>());

                        }
                    }
                }
            }
            _Data[currentLog2].Enqueue(content);
            //Write(null);
            ThreadPool.QueueUserWorkItem(Write, null);
        }

        void InitWriter(string name, 表映射 map, string content)
        {
            string fileName = string.IsNullOrEmpty(map.源表名) ? map.Id.ToString() : string.Format("{0}.{1}.{2}", map.源表名, map.目标表名, map.Id);
            InitWriter(name, fileName, content);
        }

        readonly ConcurrentDictionary<string, ConcurrentQueue<string>> _Data = new ConcurrentDictionary<string, ConcurrentQueue<string>>();
        bool _Is_Writing_Log = false;

        //static bool _Has_Files = true;

        /// <summary>
        /// 写入日志
        /// </summary>
        internal void Write(object para)
        {
            while (_Is_Writing_Log)
            {
                Thread.Sleep(10);
            }
            bool _Has_Files = true;
            while (_Has_Files)
            {
                _Is_Writing_Log = true;
                _Has_Files = false;
                Thread.Sleep(100);
                var list = _Data.Keys.ToList();
                for (int i = 0; i < list.Count; i++)
                {
                    string file = list[i];
                    ConcurrentQueue<string> _Queue = _Data[file];
                    List<string> _dd = new List<string>();
                    string content = null;
                    if (_Queue.Count == 0)
                        continue;
                    _Has_Files = true;
                    while (_Queue.Count > 0)
                    {
                        if (_Queue.TryDequeue(out content))
                            _dd.Add(content);
                    }
                    if (_dd.Count > 0)
                    {
                        bool _Has_Writed = false;
                        while (!_Has_Writed)
                        {
                            try
                            {
                                System.IO.File.AppendAllLines(file, _dd, Encoding.UTF8);
                                _Has_Writed = true;
                            }
                            catch (Exception)
                            {
                                Thread.Sleep(10);
                            }
                        }

                    }
                }
            }
            _Is_Writing_Log = false;
        }

        void InitWriter(LoggerType name, 表映射 map, string content)
        {
            InitWriter(name.ToString(), map, content);
        }

        const string COLUMN_SPILTER = "____";


        List<string> ReadLog(LoggerType name, 表映射 map)
        {
            _INIT_DIR();
            string currentLog1 = Path.Combine(LogDir, name.ToString());
            string currentLog2 = Path.Combine(currentLog1, string.Format("{0}.{1}.{2}", map.源表名, map.目标表名, map.Id));
            if (!File.Exists(currentLog2))
            {
                return new List<string>();
            }
            return File.ReadAllLines(currentLog2, Encoding.UTF8).ToList();
        }

        void _INIT_DIR()
        {
            if (string.IsNullOrEmpty(LogDir))
            {
                string software = null;
                if (string.IsNullOrEmpty(MyDbConfig.Current.日志目录))
                {
                    string documents = Environment.GetFolderPath(Environment.SpecialFolder.CommonDocuments);
                    software = Path.Combine(documents, "MyDBTransmission");
                }
                else
                {
                    software = MyDbConfig.Current.日志目录;
                }
                string log = Path.Combine(software, "Logs");
                string currentLogDir = Path.Combine(log, Id);
                LogDir = currentLogDir;
            }
        }

        public string Id { get; set; }


        public string LogDir { get; set; }



        public enum LoggerType
        {
            新增
            ,
            删除
            ,
            覆盖
            ,
            溢出
            ,
            格式错误
            ,
            跳过
            ,
            程序异常
            ,
            警告
                ,
            错误,
            信息
        }

        public void _警告(表映射 map, string warning)
        {
            InitWriter(LoggerType.警告, map, warning);
        }


        public void _信息(string warning, string group)
        {
            InitWriter(LoggerType.信息.ToString(), group, warning);
        }

        public void _警告(string warning, string group)
        {
            InitWriter(LoggerType.警告.ToString(), group, warning);

        }
        public void _错误(string fileId, Exception exp)
        {
            List<String> builder = new List<string>();
            while (exp != null)
            {
                builder.Add(exp.Message);
                builder.Add(exp.StackTrace);
                exp = exp.InnerException;
            }
            InitWriter(LoggerType.错误.ToString(), fileId, string.Join(Environment.NewLine, builder));
        }
        public void _删除(表映射 map, List<string> IdList)
        {
            InitWriter(LoggerType.删除, map, string.Join(",", IdList));
        }

        public void _删除(表映射 map, string Id)
        {
            InitWriter(LoggerType.删除, map, Id);
        }
        public void _新增(表映射 map, List<string> IdList)
        {
            InitWriter(LoggerType.新增, map, string.Join(",", IdList));
        }

        public void _新增(表映射 map, string Id)
        {
            InitWriter(LoggerType.新增, map, Id);
        }

        public void _覆盖(表映射 map, List<String> IdList)
        {
            InitWriter(LoggerType.覆盖, map, string.Join(",", IdList));
        }

        public void _覆盖(表映射 map, string Id, List<string> columns)
        {
            string content = $"{Id}{Environment.NewLine}{String.Join(",", columns)}";
            InitWriter(LoggerType.覆盖, map, content);
        }

        public void _溢出(表映射 map, string Id, string column)
        {
            InitWriter(LoggerType.溢出, map, $"{Id}  {column}");
        }

        public void _格式错误(表映射 map, string commandText, string message)
        {
            InitWriter(LoggerType.格式错误, map, $"{commandText}{Environment.NewLine}{message}");
        }

        public void _格式错误(表映射 map, string commandText, Exception exp)
        {
            List<String> builder = new List<string>();
            builder.Add(commandText);
            while (exp != null)
            {
                builder.Add(exp.Message);
                builder.Add(exp.StackTrace);
                exp = exp.InnerException;
            }
            InitWriter(LoggerType.格式错误, map, string.Join(Environment.NewLine, builder));

        }

        public void _跳过(表映射 map, string Id)
        {
            InitWriter(LoggerType.跳过, map, Id);
        }
        public void _程序异常(Exception exp, string group = null)
        {
            List<string> builder = new List<string>();
            while (exp != null)
            {
                builder.Add(exp.Message);
                builder.Add(exp.StackTrace);
                exp = exp.InnerException;
            }
            InitWriter("程序异常", group ?? "_程序异常", string.Join(Environment.NewLine, builder));
        }

        List<List<string>> ReadAllLog(表映射 map)
        {
            List<List<string>> rs = new List<List<string>>();
            string[] names = Enum.GetNames(typeof(LoggerType));
            foreach (var item in names)
            {
                LoggerType lt = (LoggerType)Enum.Parse(typeof(LoggerType), item);
                rs.Add(ReadLog(lt, map));
            }
            return rs;
        }

    }
}
